package org.springframework.beans.factory.support;

import org.springframework.beans.*;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.config.*;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.DecoratingClassLoader;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.log.LogMessage;
import org.springframework.lang.Nullable;
import org.springframework.util.*;

import java.beans.PropertyEditor;
import java.security.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Abstract base class for {@link org.springframework.beans.factory.BeanFactory}
 * implementations, providing the full capabilities of the
 * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory} SPI.
 * Does <i>not</i> assume a listable bean factory: can therefore also be used
 * as base class for bean factory implementations which obtain bean definitions
 * from some backend resource (where bean definition access is an expensive operation).
 *
 * <p>This class provides a singleton cache (through its base class
 * {@link org.springframework.beans.factory.support.DefaultSingletonBeanRegistry},
 * singleton/prototype determination, {@link org.springframework.beans.factory.FactoryBean}
 * handling, aliases, bean definition merging for child bean definitions,
 * and bean destruction ({@link org.springframework.beans.factory.DisposableBean}
 * interface, custom destroy methods). Furthermore, it can manage a bean factory
 * hierarchy (delegating to the parent in case of an unknown bean), through implementing
 * the {@link org.springframework.beans.factory.HierarchicalBeanFactory} interface.
 *
 * <p>The main template methods to be implemented by subclasses are
 * {@link #getBeanDefinition} and {@link #createBean}, retrieving a bean definition
 * for a given bean name and creating a bean instance for a given bean definition,
 * respectively. Default implementations of those operations can be found in
 * {@link DefaultListableBeanFactory} and {@link AbstractAutowireCapableBeanFactory}.
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Costin Leau
 * @author Chris Beams
 * @author Phillip Webb
 * @see #getBeanDefinition
 * @see #createBean
 * @see AbstractAutowireCapableBeanFactory#createBean
 * @see DefaultListableBeanFactory#getBeanDefinition
 * @since 15 April 2001
 */
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

    /** Parent bean factory, for bean inheritance support. */
    @Nullable
    private BeanFactory parentBeanFactory;

    /** ClassLoader to resolve bean class names with, if necessary. */
    @Nullable
    private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

    /** ClassLoader to temporarily resolve bean class names with, if necessary. */
    @Nullable
    private ClassLoader tempClassLoader;

    /** Whether to cache bean metadata or rather reobtain it for every access. */
    private boolean cacheBeanMetadata = true;

    /** Resolution strategy for expressions in bean definition values. */
    @Nullable
    private BeanExpressionResolver beanExpressionResolver;

    /** Spring ConversionService to use instead of PropertyEditors. */
    @Nullable
    private ConversionService conversionService;

    /** Custom PropertyEditorRegistrars to apply to the beans of this factory. */
    private final Set<PropertyEditorRegistrar> propertyEditorRegistrars = new LinkedHashSet<>(4);

    /** Custom PropertyEditors to apply to the beans of this factory. */
    private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors = new HashMap<>(4);

    /** A custom TypeConverter to use, overriding the default PropertyEditor mechanism. */
    @Nullable
    private TypeConverter typeConverter;

    /** String resolvers to apply e.g. to annotation attribute values. */
    private final List<StringValueResolver> embeddedValueResolvers = new CopyOnWriteArrayList<>();

    /** BeanPostProcessors to apply in createBean. */
    private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

    /** Indicates whether any InstantiationAwareBeanPostProcessors have been registered. */
    private volatile boolean hasInstantiationAwareBeanPostProcessors;

    /** Indicates whether any DestructionAwareBeanPostProcessors have been registered. */
    private volatile boolean hasDestructionAwareBeanPostProcessors;

    /** Map from scope identifier String to corresponding Scope. */
    private final Map<String, Scope> scopes = new LinkedHashMap<>(8);

    /** Security context used when running with a SecurityManager. */
    @Nullable
    private SecurityContextProvider securityContextProvider;

    /** Map from bean name to merged RootBeanDefinition. */
    private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

    /** Names of beans that have already been created at least once. */
    //不管单例还是原型，均会被标记，主要用在循环依赖无法解决的时候擦屁股用的
    private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

    /** Names of beans that are currently in creation. */
    private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal<>("Prototype beans "
            + "currently in creation");

    /**
     * Create a new AbstractBeanFactory.
     */
    public AbstractBeanFactory() {
    }

    /**
     * Create a new AbstractBeanFactory with the given parent.
     * @param parentBeanFactory parent bean factory, or {@code null} if none
     * @see #getBean
     */
    public AbstractBeanFactory(@Nullable BeanFactory parentBeanFactory) {
        this.parentBeanFactory = parentBeanFactory;
    }

    //---------------------------------------------------------------------
    // Implementation of BeanFactory interface
    //---------------------------------------------------------------------

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return doGetBean(name, requiredType, null, false);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, null, args, false);
    }

    /**
     * Return an instance, which may be shared or independent, of the specified bean.
     * @param name         the name of the bean to retrieve
     * @param requiredType the required type of the bean to retrieve
     * @param args         arguments to use when creating a bean instance using explicit arguments
     *                     (only applied when creating a new instance as opposed to retrieving an existing one)
     * @return an instance of the bean
     * @throws BeansException if the bean could not be created
     */
    public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException {

        return doGetBean(name, requiredType, args, false);
    }

    /**
     * Return an instance, which may be shared or independent, of the specified bean.
     * @param name          the name of the bean to retrieve
     * @param requiredType  the required type of the bean to retrieve
     * @param args          arguments to use when creating a bean instance using explicit arguments
     *                      (only applied when creating a new instance as opposed to retrieving an existing one)
     * @param typeCheckOnly whether the instance is obtained for a type check,
     *                      not for actual use
     * @return an instance of the bean
     * @throws BeansException if the bean could not be created
     */
    @SuppressWarnings("unchecked")
    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args
            , boolean typeCheckOnly) throws BeansException {
        //通过三种形式获取beanName
        // 一个是原始的beanName，一个是加了&的，一个是别名
        final String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        // 尝试从单例缓存集合里获取bean实例
        Object sharedInstance = getSingleton(beanName);
        //如果先前已经创建过单例Bean的实例，并且调用的getBean方法传入的参数为空
        //则执行if里面的逻辑
        //args之所以要求为空是因为如果有args，则需要做进一步赋值，因此无法直接返回
        if(sharedInstance != null && args == null){
            if(logger.isTraceEnabled()){
                //如果Bean还在创建中，则说明是循环引用
                if(isSingletonCurrentlyInCreation(beanName)){
                    logger.trace("Returning eagerly cached instance of singleton bean '"
                            + beanName
                            + "' that is not fully initialized yet - a consequence of a circular reference");
                }else{
                    logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            // 如果是普通bean，直接返回，如果是FactoryBean，则返回他的getObject
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }else{
            //若scope为prototype或者单例模式但是缓存中还不存在bean

            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            //如果scope为prototype并且显示还在创建中，则基本是循环依赖的情况
            //针对prototype的循环依赖，spring无解，直接抛出异常
            // A->B->A
            if(isPrototypeCurrentlyInCreation(beanName)){
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            BeanFactory parentBeanFactory = getParentBeanFactory();
            // 从当前容器中找不到指定名称的bean,此时递归去parentFactory查找
            if(parentBeanFactory != null && !containsBeanDefinition(beanName)){
                // Not found -> check parent.
                // 主要针对FactoryBean，将Bean的&重新加上
                String nameToLookup = originalBeanName(name);
                //如果parent容器依旧是AbstractBeanFactory的实例
                //instanceof通过返回一个布尔值来指出，这个对象是否是这个特定类或者是它的子类的一个实例
                if(parentBeanFactory instanceof AbstractBeanFactory){
                    //直接递归调用方法来查找
                    return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args,
                            typeCheckOnly);
                }else if(args != null){
                    // Delegation to parent with explicit args.
                    // 如果有参数，则委派父级容器根据指定名称和显式的参数查找
                    return (T)parentBeanFactory.getBean(nameToLookup, args);
                }else if(requiredType != null){
                    // No args -> delegate to standard getBean method.
                    //委派父级容器根据指定名称和类型查找
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }else{
                    //委派父级容器根据指定名称查找
                    return (T)parentBeanFactory.getBean(nameToLookup);
                }
            }
            //typeCheckOnly 是用来判断调用 getBean() 是否仅仅是为了类型检查获取 bean，而不是为了创建Bean
            if(!typeCheckOnly){
                // 如果不是仅仅做类型检查则是创建bean
                markBeanAsCreated(beanName);
            }

            try{
                //将父类的BeanDefinition与子类的BeanDefinition进行合并覆盖
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                //对合并的BeanDefinition做验证，主要看属性是否为abstract的
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                // 获取当前Bean所有依赖Bean的名称
                String[] dependsOn = mbd.getDependsOn();
                // 如果当前Bean设置了dependsOn的属性
                //depends-on用来指定Bean初始化及销毁时的顺序
                //<bean id=a Class="com.imooc.A" depends-on="b" />
                // <bean id=b Class="com.imooc.B" />
                if(dependsOn != null){
                    for(String dep: dependsOn){
                        //校验该依赖是否已经注册给当前 bean,注意这里传入的key是当前的bean名称
                        //这里主要是判断是否有以下这种类型的依赖：
                        //<bean id="beanA" class="BeanA" depends-on="beanB">
                        //<bean id="beanB" class="BeanB" depends-on="beanA">
                        //如果有，则直接抛出异常
                        if(isDependent(beanName, dep)){
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '"
                                            + beanName
                                            + "' and '"
                                            + dep
                                            + "'");
                        }
                        //缓存依赖调用，注意这里传入的key是被依赖的bean名称
                        registerDependentBean(dep, beanName);
                        try{
                            //递归调用getBean方法，注册Bean之间的依赖（如C需要晚于B初始化，而B需要晚于A初始化）
                            // 初始化依赖的bean
                            getBean(dep);
                        }catch(NoSuchBeanDefinitionException ex){
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'"
                                    + beanName
                                    + "' depends on missing bean '"
                                    + dep
                                    + "'", ex);
                        }
                    }
                }

                // Create bean instance.
                //如果BeanDefinition为单例
                if(mbd.isSingleton()){
                    //这里使用了一个匿名内部类，创建Bean实例对象，并且注册给所依赖的对象
                    sharedInstance = getSingleton(beanName, () -> {
                        try{
                            return createBean(beanName, mbd, args);
                        }catch(BeansException ex){
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            // 显式从单例缓存中删除 bean 实例
                            // 因为单例模式下为了解决循环依赖，可能它已经存在了，所以将其销毁
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    // 如果是普通bean，直接返回，是FactoryBean，返回他的getObject
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }else if(mbd.isPrototype()){
                    // It's a prototype -> create a new instance.
                    //Prototype每次都会创建一个新的对象
                    Object prototypeInstance = null;
                    try{
                        //默认的功能是注册当前创建的prototype对象为正在创建中
                        beforePrototypeCreation(beanName);
                        //创建原型对象实例
                        prototypeInstance = createBean(beanName, mbd, args);
                    }finally{
                        //默认的功能是将先前注册的正在创建中的Bean信息给抹除掉
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                //要创建的Bean既不是单态模式，也不是原型模式，则根据Bean定义资源中
                //配置的生命周期范围，选择实例化Bean的合适方法，这种在Web应用程序中
                //比较常用，如：request、session、application等生命周期
                else{
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    //Bean定义资源中没有配置生命周期范围，则Bean定义不合法
                    if(scope == null){
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try{
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try{
                                return createBean(beanName, mbd, args);
                            }finally{
                                afterPrototypeCreation(beanName);
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }catch(IllegalStateException ex){
                        throw new BeanCreationException(beanName, "Scope '"
                                + scopeName
                                + "' is not active for the current thread; consider "
                                + "defining a scoped proxy for this bean if you intend to refer to it from a "
                                + "singleton", ex);
                    }
                }
            }catch(BeansException ex){
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // Check if required type matches the type of the actual bean instance.
        //对创建的Bean实例对象进行类型检查
        if(requiredType != null && !requiredType.isInstance(bean)){
            try{
                T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if(convertedBean == null){
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            }catch(TypeMismatchException ex){
                if(logger.isTraceEnabled()){
                    logger.trace("Failed to convert bean '"
                            + name
                            + "' to required type '"
                            + ClassUtils.getQualifiedName(requiredType)
                            + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T)bean;
    }

    @Override
    public boolean containsBean(String name) {
        String beanName = transformedBeanName(name);
        // 已创建单例bean或者包括bean的定义
        if(containsSingleton(beanName) || containsBeanDefinition(beanName)){
            // 如果不是&开头的，直接返回
            // 如果是&开头的，判断是否是FactoryBean，没有找到从父类找
            return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
        }
        // Not found -> check parent.
        // 当前容器没找到，去父类找
        BeanFactory parentBeanFactory = getParentBeanFactory();
        return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
    }

    @Override
    public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
        String beanName = transformedBeanName(name);

        Object beanInstance = getSingleton(beanName, false);
        if(beanInstance != null){
            if(beanInstance instanceof FactoryBean){
                return (BeanFactoryUtils.isFactoryDereference(name) || ((FactoryBean<?>)beanInstance).isSingleton());
            }else{
                return !BeanFactoryUtils.isFactoryDereference(name);
            }
        }

        // No singleton instance found -> check bean definition.
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if(parentBeanFactory != null && !containsBeanDefinition(beanName)){
            // No bean definition found in this factory -> delegate to parent.
            return parentBeanFactory.isSingleton(originalBeanName(name));
        }

        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

        // In case of FactoryBean, return singleton status of created object if not a dereference.
        if(mbd.isSingleton()){
            if(isFactoryBean(beanName, mbd)){
                if(BeanFactoryUtils.isFactoryDereference(name)){
                    return true;
                }
                FactoryBean<?> factoryBean = (FactoryBean<?>)getBean(FACTORY_BEAN_PREFIX + beanName);
                return factoryBean.isSingleton();
            }else{
                return !BeanFactoryUtils.isFactoryDereference(name);
            }
        }else{
            return false;
        }
    }

    @Override
    public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
        String beanName = transformedBeanName(name);

        BeanFactory parentBeanFactory = getParentBeanFactory();
        if(parentBeanFactory != null && !containsBeanDefinition(beanName)){
            // No bean definition found in this factory -> delegate to parent.
            return parentBeanFactory.isPrototype(originalBeanName(name));
        }

        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        if(mbd.isPrototype()){
            // In case of FactoryBean, return singleton status of created object if not a dereference.
            return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName, mbd));
        }

        // Singleton or scoped - not a prototype.
        // However, FactoryBean may still produce a prototype object...
        if(BeanFactoryUtils.isFactoryDereference(name)){
            return false;
        }
        if(isFactoryBean(beanName, mbd)){
            final FactoryBean<?> fb = (FactoryBean<?>)getBean(FACTORY_BEAN_PREFIX + beanName);
            if(System.getSecurityManager() != null){
                return AccessController.doPrivileged((PrivilegedAction<Boolean>)() -> ((fb instanceof SmartFactoryBean
                        && ((SmartFactoryBean<?>)fb).isPrototype()) || !fb.isSingleton()), getAccessControlContext());
            }else{
                return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>)fb).isPrototype())
                        || !fb.isSingleton());
            }
        }else{
            return false;
        }
    }

    @Override
    public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException {
        return isTypeMatch(name, typeToMatch, true);
    }

    /**
     * Internal extended variant of {@link #isTypeMatch(String, ResolvableType)}
     * to check whether the bean with the given name matches the specified type. Allow
     * additional constraints to be applied to ensure that beans are not created early.
     * @param name        the name of the bean to query
     * @param typeToMatch the type to match against (as a
     *                    {@code ResolvableType})
     * @return {@code true} if the bean type matches, {@code false} if it
     *         doesn't match or cannot be determined yet
     * @throws NoSuchBeanDefinitionException if there is no bean with the given name
     * @see #getBean
     * @see #getType
     * @since 5.2
     */
    protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException {

        String beanName = transformedBeanName(name);
        boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);

        // Check manually registered singletons.
        // 获取单例
        Object beanInstance = getSingleton(beanName, false);
        // 不为空并且不是NullBean类型
        if(beanInstance != null && beanInstance.getClass() != NullBean.class){
            if(beanInstance instanceof FactoryBean){
                if(!isFactoryDereference){
                    // 不是&开头，获取FactoryBean的getObjectType类型，再来比较
                    Class<?> type = getTypeForFactoryBean((FactoryBean<?>)beanInstance);
                    return (type != null && typeToMatch.isAssignableFrom(type));
                }else{
                    // name是&开头，直接判断类型FactoryBean
                    return typeToMatch.isInstance(beanInstance);
                }
            }
            // 普通bean，且没有&开头
            else if(!isFactoryDereference){
                if(typeToMatch.isInstance(beanInstance)){
                    // Direct match for the exposed instance?
                    return true;
                }
                // 泛型且有beanName的定义
                else if(typeToMatch.hasGenerics() && containsBeanDefinition(beanName)){
                    // Generics potentially only match on the target class, not on the proxy...
                    // 合并定义
                    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    Class<?> targetType = mbd.getTargetType();
                    if(targetType != null && targetType != ClassUtils.getUserClass(beanInstance)){
                        // Check raw class match as well, making sure it's exposed on the proxy.
                        Class<?> classToMatch = typeToMatch.resolve();
                        if(classToMatch != null && !classToMatch.isInstance(beanInstance)){
                            return false;
                        }
                        if(typeToMatch.isAssignableFrom(targetType)){
                            return true;
                        }
                    }
                    ResolvableType resolvableType = mbd.targetType;
                    if(resolvableType == null){
                        resolvableType = mbd.factoryMethodReturnType;
                    }
                    return (resolvableType != null && typeToMatch.isAssignableFrom(resolvableType));
                }
            }
            return false;
        }
        // 已经创建了，但是没有bean的定义，说明是空的注册进来
        else if(containsSingleton(beanName) && !containsBeanDefinition(beanName)){
            // null instance registered
            return false;
        }

        // No singleton instance found -> check bean definition.
        // 从父类容器找
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if(parentBeanFactory != null && !containsBeanDefinition(beanName)){
            // No bean definition found in this factory -> delegate to parent.
            return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
        }

        // Retrieve corresponding bean definition.
        //将父类的定义的BeanDefinition与子类的BeanDefinition进行合并覆盖
        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();

        // Setup the types that we want to match against
        Class<?> classToMatch = typeToMatch.resolve();
        if(classToMatch == null){
            classToMatch = FactoryBean.class;
        }
        Class<?>[] typesToMatch = (FactoryBean.class
                                           == classToMatch?new Class<?>[]{classToMatch}:
                                   new Class<?>[]{FactoryBean.class, classToMatch});

        // Attempt to predict the bean type
        Class<?> predictedType = null;

        // We're looking for a regular reference but we're a factory bean that has
        // a decorated bean definition. The target bean should be the same type
        // as FactoryBean would ultimately return.
        if(!isFactoryDereference && dbd != null && isFactoryBean(beanName, mbd)){
            // We should only attempt if the user explicitly set lazy-init to true
            // and we know the merged bean definition is for a factory bean.
            if(!mbd.isLazyInit() || allowFactoryBeanInit){
                RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
                Class<?> targetType = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
                if(targetType != null && !FactoryBean.class.isAssignableFrom(targetType)){
                    predictedType = targetType;
                }
            }
        }

        // If we couldn't use the target type, try regular prediction.
        if(predictedType == null){
            predictedType = predictBeanType(beanName, mbd, typesToMatch);
            if(predictedType == null){
                return false;
            }
        }

        // Attempt to get the actual ResolvableType for the bean.
        ResolvableType beanType = null;

        // If it's a FactoryBean, we want to look at what it creates, not the factory class.
        if(FactoryBean.class.isAssignableFrom(predictedType)){
            if(beanInstance == null && !isFactoryDereference){
                beanType = getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit);
                predictedType = beanType.resolve();
                if(predictedType == null){
                    return false;
                }
            }
        }else if(isFactoryDereference){
            // Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
            // type but we nevertheless are being asked to dereference a FactoryBean...
            // Let's check the original bean class and proceed with it if it is a FactoryBean.
            predictedType = predictBeanType(beanName, mbd, FactoryBean.class);
            if(predictedType == null || !FactoryBean.class.isAssignableFrom(predictedType)){
                return false;
            }
        }

        // We don't have an exact type but if bean definition target type or the factory
        // method return type matches the predicted type then we can use that.
        if(beanType == null){
            ResolvableType definedType = mbd.targetType;
            if(definedType == null){
                definedType = mbd.factoryMethodReturnType;
            }
            if(definedType != null && definedType.resolve() == predictedType){
                beanType = definedType;
            }
        }

        // If we have a bean type use it so that generics are considered
        if(beanType != null){
            return typeToMatch.isAssignableFrom(beanType);
        }

        // If we don't have a bean type, fallback to the predicted type
        return typeToMatch.isAssignableFrom(predictedType);
    }

    @Override
    public boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException {
        return isTypeMatch(name, ResolvableType.forRawClass(typeToMatch));
    }

    @Override
    @Nullable
    public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
        return getType(name, true);
    }

    @Override
    @Nullable
    public Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException {
        String beanName = transformedBeanName(name);

        // Check manually registered singletons.
        Object beanInstance = getSingleton(beanName, false);
        if(beanInstance != null && beanInstance.getClass() != NullBean.class){
            if(beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)){
                return getTypeForFactoryBean((FactoryBean<?>)beanInstance);
            }else{
                return beanInstance.getClass();
            }
        }

        // No singleton instance found -> check bean definition.
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if(parentBeanFactory != null && !containsBeanDefinition(beanName)){
            // No bean definition found in this factory -> delegate to parent.
            return parentBeanFactory.getType(originalBeanName(name));
        }

        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

        // Check decorated bean definition, if any: We assume it'll be easier
        // to determine the decorated bean's type than the proxy's type.
        BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
        if(dbd != null && !BeanFactoryUtils.isFactoryDereference(name)){
            RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
            Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd);
            if(targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)){
                return targetClass;
            }
        }

        Class<?> beanClass = predictBeanType(beanName, mbd);

        // Check bean class whether we're dealing with a FactoryBean.
        if(beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)){
            if(!BeanFactoryUtils.isFactoryDereference(name)){
                // If it's a FactoryBean, we want to look at what it creates, not at the factory class.
                return getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit).resolve();
            }else{
                return beanClass;
            }
        }else{
            return (!BeanFactoryUtils.isFactoryDereference(name)?beanClass:null);
        }
    }

    @Override
    public String[] getAliases(String name) {
        String beanName = transformedBeanName(name);
        List<String> aliases = new ArrayList<>();
        boolean factoryPrefix = name.startsWith(FACTORY_BEAN_PREFIX);
        String fullBeanName = beanName;
        if(factoryPrefix){
            fullBeanName = FACTORY_BEAN_PREFIX + beanName;
        }
        if(!fullBeanName.equals(name)){
            aliases.add(fullBeanName);
        }
        String[] retrievedAliases = super.getAliases(beanName);
        for(String retrievedAlias: retrievedAliases){
            String alias = (factoryPrefix?FACTORY_BEAN_PREFIX:"") + retrievedAlias;
            if(!alias.equals(name)){
                aliases.add(alias);
            }
        }
        if(!containsSingleton(beanName) && !containsBeanDefinition(beanName)){
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if(parentBeanFactory != null){
                aliases.addAll(Arrays.asList(parentBeanFactory.getAliases(fullBeanName)));
            }
        }
        return StringUtils.toStringArray(aliases);
    }

    //---------------------------------------------------------------------
    // Implementation of HierarchicalBeanFactory interface
    //---------------------------------------------------------------------

    @Override
    @Nullable
    public BeanFactory getParentBeanFactory() {
        return this.parentBeanFactory;
    }

    @Override
    public boolean containsLocalBean(String name) {
        String beanName = transformedBeanName(name);
        return ((containsSingleton(beanName) || containsBeanDefinition(beanName))
                && (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName)));
    }

    //---------------------------------------------------------------------
    // Implementation of ConfigurableBeanFactory interface
    //---------------------------------------------------------------------

    @Override
    public void setParentBeanFactory(@Nullable BeanFactory parentBeanFactory) {
        if(this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory){
            throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory);
        }
        this.parentBeanFactory = parentBeanFactory;
    }

    @Override
    public void setBeanClassLoader(@Nullable ClassLoader beanClassLoader) {
        this.beanClassLoader = (beanClassLoader != null?beanClassLoader:ClassUtils.getDefaultClassLoader());
    }

    @Override
    @Nullable
    public ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }

    @Override
    public void setTempClassLoader(@Nullable ClassLoader tempClassLoader) {
        this.tempClassLoader = tempClassLoader;
    }

    @Override
    @Nullable
    public ClassLoader getTempClassLoader() {
        return this.tempClassLoader;
    }

    @Override
    public void setCacheBeanMetadata(boolean cacheBeanMetadata) {
        this.cacheBeanMetadata = cacheBeanMetadata;
    }

    @Override
    public boolean isCacheBeanMetadata() {
        return this.cacheBeanMetadata;
    }

    @Override
    public void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver) {
        this.beanExpressionResolver = resolver;
    }

    @Override
    @Nullable
    public BeanExpressionResolver getBeanExpressionResolver() {
        return this.beanExpressionResolver;
    }

    @Override
    public void setConversionService(@Nullable ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    @Override
    @Nullable
    public ConversionService getConversionService() {
        return this.conversionService;
    }

    @Override
    public void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar) {
        Assert.notNull(registrar, "PropertyEditorRegistrar must not be null");
        this.propertyEditorRegistrars.add(registrar);
    }

    /**
     * Return the set of PropertyEditorRegistrars.
     */
    public Set<PropertyEditorRegistrar> getPropertyEditorRegistrars() {
        return this.propertyEditorRegistrars;
    }

    @Override
    public void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass) {
        Assert.notNull(requiredType, "Required type must not be null");
        Assert.notNull(propertyEditorClass, "PropertyEditor class must not be null");
        this.customEditors.put(requiredType, propertyEditorClass);
    }

    @Override
    public void copyRegisteredEditorsTo(PropertyEditorRegistry registry) {
        registerCustomEditors(registry);
    }

    /**
     * Return the map of custom editors, with Classes as keys and PropertyEditor classes as values.
     */
    public Map<Class<?>, Class<? extends PropertyEditor>> getCustomEditors() {
        return this.customEditors;
    }

    @Override
    public void setTypeConverter(TypeConverter typeConverter) {
        this.typeConverter = typeConverter;
    }

    /**
     * Return the custom TypeConverter to use, if any.
     * @return the custom TypeConverter, or {@code null} if none specified
     */
    @Nullable
    protected TypeConverter getCustomTypeConverter() {
        return this.typeConverter;
    }

    @Override
    public TypeConverter getTypeConverter() {
        TypeConverter customConverter = getCustomTypeConverter();
        if(customConverter != null){
            return customConverter;
        }else{
            // Build default TypeConverter, registering custom editors.
            SimpleTypeConverter typeConverter = new SimpleTypeConverter();
            typeConverter.setConversionService(getConversionService());
            registerCustomEditors(typeConverter);
            return typeConverter;
        }
    }

    @Override
    public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
        Assert.notNull(valueResolver, "StringValueResolver must not be null");
        this.embeddedValueResolvers.add(valueResolver);
    }

    @Override
    public boolean hasEmbeddedValueResolver() {
        return !this.embeddedValueResolvers.isEmpty();
    }

    @Override
    @Nullable
    public String resolveEmbeddedValue(@Nullable String value) {
        if(value == null){
            return null;
        }
        String result = value;
        for(StringValueResolver resolver: this.embeddedValueResolvers){
            result = resolver.resolveStringValue(result);
            if(result == null){
                return null;
            }
        }
        return result;
    }

    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
        // Remove from old position, if any
        this.beanPostProcessors.remove(beanPostProcessor);
        // Track whether it is instantiation/destruction aware
        if(beanPostProcessor instanceof InstantiationAwareBeanPostProcessor){
            this.hasInstantiationAwareBeanPostProcessors = true;
        }
        if(beanPostProcessor instanceof DestructionAwareBeanPostProcessor){
            this.hasDestructionAwareBeanPostProcessors = true;
        }
        // Add to end of list
        this.beanPostProcessors.add(beanPostProcessor);
    }

    @Override
    public int getBeanPostProcessorCount() {
        return this.beanPostProcessors.size();
    }

    /**
     * Return the list of BeanPostProcessors that will get applied
     * to beans created with this factory.
     */
    public List<BeanPostProcessor> getBeanPostProcessors() {
        return this.beanPostProcessors;
    }

    /**
     * Return whether this factory holds a InstantiationAwareBeanPostProcessor
     * that will get applied to singleton beans on shutdown.
     * @see #addBeanPostProcessor
     * @see org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
     */
    protected boolean hasInstantiationAwareBeanPostProcessors() {
        return this.hasInstantiationAwareBeanPostProcessors;
    }

    /**
     * Return whether this factory holds a DestructionAwareBeanPostProcessor
     * that will get applied to singleton beans on shutdown.
     * @see #addBeanPostProcessor
     * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
     */
    protected boolean hasDestructionAwareBeanPostProcessors() {
        return this.hasDestructionAwareBeanPostProcessors;
    }

    @Override
    public void registerScope(String scopeName, Scope scope) {
        Assert.notNull(scopeName, "Scope identifier must not be null");
        Assert.notNull(scope, "Scope must not be null");
        if(SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)){
            throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'");
        }
        Scope previous = this.scopes.put(scopeName, scope);
        if(previous != null && previous != scope){
            if(logger.isDebugEnabled()){
                logger.debug("Replacing scope '" + scopeName + "' from [" + previous + "] to [" + scope + "]");
            }
        }else{
            if(logger.isTraceEnabled()){
                logger.trace("Registering scope '" + scopeName + "' with implementation [" + scope + "]");
            }
        }
    }

    @Override
    public String[] getRegisteredScopeNames() {
        return StringUtils.toStringArray(this.scopes.keySet());
    }

    @Override
    @Nullable
    public Scope getRegisteredScope(String scopeName) {
        Assert.notNull(scopeName, "Scope identifier must not be null");
        return this.scopes.get(scopeName);
    }

    /**
     * Set the security context provider for this bean factory. If a security manager
     * is set, interaction with the user code will be executed using the privileged
     * of the provided security context.
     */
    public void setSecurityContextProvider(SecurityContextProvider securityProvider) {
        this.securityContextProvider = securityProvider;
    }

    /**
     * Delegate the creation of the access control context to the
     * {@link #setSecurityContextProvider SecurityContextProvider}.
     */
    @Override
    public AccessControlContext getAccessControlContext() {
        return (this.securityContextProvider
                        != null?this.securityContextProvider.getAccessControlContext():AccessController.getContext());
    }

    @Override
    public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
        Assert.notNull(otherFactory, "BeanFactory must not be null");
        setBeanClassLoader(otherFactory.getBeanClassLoader());
        setCacheBeanMetadata(otherFactory.isCacheBeanMetadata());
        setBeanExpressionResolver(otherFactory.getBeanExpressionResolver());
        setConversionService(otherFactory.getConversionService());
        if(otherFactory instanceof AbstractBeanFactory){
            AbstractBeanFactory otherAbstractFactory = (AbstractBeanFactory)otherFactory;
            this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars);
            this.customEditors.putAll(otherAbstractFactory.customEditors);
            this.typeConverter = otherAbstractFactory.typeConverter;
            this.beanPostProcessors.addAll(otherAbstractFactory.beanPostProcessors);
            this.hasInstantiationAwareBeanPostProcessors = this.hasInstantiationAwareBeanPostProcessors
                    || otherAbstractFactory.hasInstantiationAwareBeanPostProcessors;
            this.hasDestructionAwareBeanPostProcessors = this.hasDestructionAwareBeanPostProcessors
                    || otherAbstractFactory.hasDestructionAwareBeanPostProcessors;
            this.scopes.putAll(otherAbstractFactory.scopes);
            this.securityContextProvider = otherAbstractFactory.securityContextProvider;
        }else{
            setTypeConverter(otherFactory.getTypeConverter());
            String[] otherScopeNames = otherFactory.getRegisteredScopeNames();
            for(String scopeName: otherScopeNames){
                this.scopes.put(scopeName, otherFactory.getRegisteredScope(scopeName));
            }
        }
    }

    /**
     * Return a 'merged' BeanDefinition for the given bean name,
     * merging a child bean definition with its parent if necessary.
     * <p>This {@code getMergedBeanDefinition} considers bean definition
     * in ancestors as well.
     * @param name the name of the bean to retrieve the merged definition for
     *             (may be an alias)
     * @return a (potentially merged) RootBeanDefinition for the given bean
     * @throws NoSuchBeanDefinitionException if there is no bean with the given name
     * @throws BeanDefinitionStoreException  in case of an invalid bean definition
     */
    @Override
    public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
        String beanName = transformedBeanName(name);
        // Efficiently check whether bean definition exists in this factory.
        if(!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory){
            return ((ConfigurableBeanFactory)getParentBeanFactory()).getMergedBeanDefinition(beanName);
        }
        // Resolve merged bean definition locally.
        return getMergedLocalBeanDefinition(beanName);
    }

    @Override
    public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
        String beanName = transformedBeanName(name);
        Object beanInstance = getSingleton(beanName, false);
        if(beanInstance != null){
            return (beanInstance instanceof FactoryBean);
        }
        // No singleton instance found -> check bean definition.
        if(!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory){
            // No bean definition found in this factory -> delegate to parent.
            return ((ConfigurableBeanFactory)getParentBeanFactory()).isFactoryBean(name);
        }
        return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
    }

    @Override
    public boolean isActuallyInCreation(String beanName) {
        return (isSingletonCurrentlyInCreation(beanName) || isPrototypeCurrentlyInCreation(beanName));
    }

    /**
     * Return whether the specified prototype bean is currently in creation
     * (within the current thread).
     * @param beanName the name of the bean
     */
    protected boolean isPrototypeCurrentlyInCreation(String beanName) {
        Object curVal = this.prototypesCurrentlyInCreation.get();
        return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set
                && ((Set<?>)curVal).contains(beanName))));
    }

    /**
     * Callback before prototype creation.
     * <p>The default implementation register the prototype as currently in creation.
     * @param beanName the name of the prototype about to be created
     * @see #isPrototypeCurrentlyInCreation
     */
    @SuppressWarnings("unchecked")
    protected void beforePrototypeCreation(String beanName) {
        Object curVal = this.prototypesCurrentlyInCreation.get();
        if(curVal == null){
            this.prototypesCurrentlyInCreation.set(beanName);
        }else if(curVal instanceof String){
            Set<String> beanNameSet = new HashSet<>(2);
            beanNameSet.add((String)curVal);
            beanNameSet.add(beanName);
            this.prototypesCurrentlyInCreation.set(beanNameSet);
        }else{
            Set<String> beanNameSet = (Set<String>)curVal;
            beanNameSet.add(beanName);
        }
    }

    /**
     * Callback after prototype creation.
     * <p>The default implementation marks the prototype as not in creation anymore.
     * @param beanName the name of the prototype that has been created
     * @see #isPrototypeCurrentlyInCreation
     */
    @SuppressWarnings("unchecked")
    protected void afterPrototypeCreation(String beanName) {
        Object curVal = this.prototypesCurrentlyInCreation.get();
        if(curVal instanceof String){
            this.prototypesCurrentlyInCreation.remove();
        }else if(curVal instanceof Set){
            Set<String> beanNameSet = (Set<String>)curVal;
            beanNameSet.remove(beanName);
            if(beanNameSet.isEmpty()){
                this.prototypesCurrentlyInCreation.remove();
            }
        }
    }

    @Override
    public void destroyBean(String beanName, Object beanInstance) {
        destroyBean(beanName, beanInstance, getMergedLocalBeanDefinition(beanName));
    }

    /**
     * Destroy the given bean instance (usually a prototype instance
     * obtained from this factory) according to the given bean definition.
     * @param beanName the name of the bean definition
     * @param bean     the bean instance to destroy
     * @param mbd      the merged bean definition
     */
    protected void destroyBean(String beanName, Object bean, RootBeanDefinition mbd) {
        new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), getAccessControlContext()).destroy();
    }

    @Override
    public void destroyScopedBean(String beanName) {
        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        if(mbd.isSingleton() || mbd.isPrototype()){
            throw new IllegalArgumentException("Bean name '"
                    + beanName
                    + "' does not correspond to an object in a mutable scope");
        }
        String scopeName = mbd.getScope();
        Scope scope = this.scopes.get(scopeName);
        if(scope == null){
            throw new IllegalStateException("No Scope SPI registered for scope name '" + scopeName + "'");
        }
        Object bean = scope.remove(beanName);
        if(bean != null){
            destroyBean(beanName, bean, mbd);
        }
    }

    //---------------------------------------------------------------------
    // Implementation methods
    //---------------------------------------------------------------------

    /**
     * Return the bean name, stripping out the factory dereference prefix if necessary,
     * and resolving aliases to canonical names.
     * @param name the user-specified name
     * @return the transformed bean name
     */
    protected String transformedBeanName(String name) {
        return canonicalName(BeanFactoryUtils.transformedBeanName(name));
    }

    /**
     * Determine the original bean name, resolving locally defined aliases to canonical names.
     * @param name the user-specified name
     * @return the original bean name
     */
    protected String originalBeanName(String name) {
        String beanName = transformedBeanName(name);
        if(name.startsWith(FACTORY_BEAN_PREFIX)){
            beanName = FACTORY_BEAN_PREFIX + beanName;
        }
        return beanName;
    }

    /**
     * Initialize the given BeanWrapper with the custom editors registered
     * with this factory. To be called for BeanWrappers that will create
     * and populate bean instances.
     * <p>The default implementation delegates to {@link #registerCustomEditors}.
     * Can be overridden in subclasses.
     * @param bw the BeanWrapper to initialize
     */
    protected void initBeanWrapper(BeanWrapper bw) {
        bw.setConversionService(getConversionService());
        registerCustomEditors(bw);
    }

    /**
     * Initialize the given PropertyEditorRegistry with the custom editors
     * that have been registered with this BeanFactory.
     * <p>To be called for BeanWrappers that will create and populate bean
     * instances, and for SimpleTypeConverter used for constructor argument
     * and factory method type conversion.
     * @param registry the PropertyEditorRegistry to initialize
     */
    protected void registerCustomEditors(PropertyEditorRegistry registry) {
        PropertyEditorRegistrySupport registrySupport = (registry instanceof PropertyEditorRegistrySupport?
                                                         (PropertyEditorRegistrySupport)registry:null);
        if(registrySupport != null){
            registrySupport.useConfigValueEditors();
        }
        if(!this.propertyEditorRegistrars.isEmpty()){
            for(PropertyEditorRegistrar registrar: this.propertyEditorRegistrars){
                try{
                    registrar.registerCustomEditors(registry);
                }catch(BeanCreationException ex){
                    Throwable rootCause = ex.getMostSpecificCause();
                    if(rootCause instanceof BeanCurrentlyInCreationException){
                        BeanCreationException bce = (BeanCreationException)rootCause;
                        String bceBeanName = bce.getBeanName();
                        if(bceBeanName != null && isCurrentlyInCreation(bceBeanName)){
                            if(logger.isDebugEnabled()){
                                logger.debug("PropertyEditorRegistrar ["
                                        + registrar.getClass().getName()
                                        + "] failed because it tried to obtain currently created bean '"
                                        + ex.getBeanName()
                                        + "': "
                                        + ex.getMessage());
                            }
                            onSuppressedException(ex);
                            continue;
                        }
                    }
                    throw ex;
                }
            }
        }
        if(!this.customEditors.isEmpty()){
            this.customEditors.forEach((requiredType, editorClass) -> registry.registerCustomEditor(requiredType,
                    BeanUtils
                    .instantiateClass(editorClass)));
        }
    }

    /**
     * Return a merged RootBeanDefinition, traversing the parent bean definition
     * if the specified bean corresponds to a child bean definition.
     * @param beanName the name of the bean to retrieve the merged definition for
     * @return a (potentially merged) RootBeanDefinition for the given bean
     * @throws NoSuchBeanDefinitionException if there is no bean with the given name
     * @throws BeanDefinitionStoreException  in case of an invalid bean definition
     */
    protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
        // Quick check on the concurrent map first, with minimal locking.
        RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
        if(mbd != null && !mbd.stale){
            return mbd;
        }
        return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
    }

    /**
     * Return a RootBeanDefinition for the given top-level bean, by merging with
     * the parent if the given bean's definition is a child bean definition.
     * @param beanName the name of the bean definition
     * @param bd       the original bean definition (Root/ChildBeanDefinition)
     * @return a (potentially merged) RootBeanDefinition for the given bean
     * @throws BeanDefinitionStoreException in case of an invalid bean definition
     */
    protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd) throws BeanDefinitionStoreException {

        return getMergedBeanDefinition(beanName, bd, null);
    }

    /**
     * Return a RootBeanDefinition for the given bean, by merging with the
     * parent if the given bean's definition is a child bean definition.
     * @param beanName     the name of the bean definition
     * @param bd           the original bean definition (Root/ChildBeanDefinition)
     * @param containingBd the containing bean definition in case of inner bean,
     *                     or {@code null} in case of a top-level bean
     * @return a (potentially merged) RootBeanDefinition for the given bean
     * @throws BeanDefinitionStoreException in case of an invalid bean definition
     */
    protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd,
                                                         @Nullable BeanDefinition containingBd) throws BeanDefinitionStoreException {

        synchronized(this.mergedBeanDefinitions){
            RootBeanDefinition mbd = null;
            RootBeanDefinition previous = null;

            // Check with full lock now in order to enforce the same merged instance.
            if(containingBd == null){
                mbd = this.mergedBeanDefinitions.get(beanName);
            }

            if(mbd == null || mbd.stale){
                previous = mbd;
                mbd = null;
                if(bd.getParentName() == null){
                    // Use copy of given root bean definition.
                    if(bd instanceof RootBeanDefinition){
                        mbd = ((RootBeanDefinition)bd).cloneBeanDefinition();
                    }else{
                        mbd = new RootBeanDefinition(bd);
                    }
                }else{
                    // Child bean definition: needs to be merged with parent.
                    BeanDefinition pbd;
                    try{
                        String parentBeanName = transformedBeanName(bd.getParentName());
                        if(!beanName.equals(parentBeanName)){
                            pbd = getMergedBeanDefinition(parentBeanName);
                        }else{
                            BeanFactory parent = getParentBeanFactory();
                            if(parent instanceof ConfigurableBeanFactory){
                                pbd = ((ConfigurableBeanFactory)parent).getMergedBeanDefinition(parentBeanName);
                            }else{
                                throw new NoSuchBeanDefinitionException(parentBeanName, "Parent name '"
                                        + parentBeanName
                                        + "' is equal to bean name '"
                                        + beanName
                                        + "': cannot be resolved without an AbstractBeanFactory parent");
                            }
                        }
                    }catch(NoSuchBeanDefinitionException ex){
                        throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                                "Could not resolve parent bean definition '"
                                        + bd.getParentName()
                                        + "'", ex);
                    }
                    // Deep copy with overridden values.
                    mbd = new RootBeanDefinition(pbd);
                    mbd.overrideFrom(bd);
                }

                // Set default singleton scope, if not configured before.
                if(!StringUtils.hasLength(mbd.getScope())){
                    mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
                }

                // A bean contained in a non-singleton bean cannot be a singleton itself.
                // Let's correct this on the fly here, since this might be the result of
                // parent-child merging for the outer bean, in which case the original inner bean
                // definition will not have inherited the merged outer bean's singleton status.
                if(containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()){
                    mbd.setScope(containingBd.getScope());
                }

                // Cache the merged bean definition for the time being
                // (it might still get re-merged later on in order to pick up metadata changes)
                if(containingBd == null && isCacheBeanMetadata()){
                    this.mergedBeanDefinitions.put(beanName, mbd);
                }
            }
            if(previous != null){
                copyRelevantMergedBeanDefinitionCaches(previous, mbd);
            }
            return mbd;
        }
    }

    private void copyRelevantMergedBeanDefinitionCaches(RootBeanDefinition previous, RootBeanDefinition mbd) {
        if(ObjectUtils.nullSafeEquals(mbd.getBeanClassName(), previous.getBeanClassName())
                && ObjectUtils.nullSafeEquals(mbd.getFactoryBeanName(), previous.getFactoryBeanName())
                && ObjectUtils.nullSafeEquals(mbd.getFactoryMethodName(), previous.getFactoryMethodName())){
            ResolvableType targetType = mbd.targetType;
            ResolvableType previousTargetType = previous.targetType;
            if(targetType == null || targetType.equals(previousTargetType)){
                mbd.targetType = previousTargetType;
                mbd.isFactoryBean = previous.isFactoryBean;
                mbd.resolvedTargetType = previous.resolvedTargetType;
                mbd.factoryMethodReturnType = previous.factoryMethodReturnType;
                mbd.factoryMethodToIntrospect = previous.factoryMethodToIntrospect;
            }
        }
    }

    /**
     * Check the given merged bean definition,
     * potentially throwing validation exceptions.
     * @param mbd      the merged bean definition to check
     * @param beanName the name of the bean
     * @param args     the arguments for bean creation, if any
     * @throws BeanDefinitionStoreException in case of validation failure
     */
    protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args) throws BeanDefinitionStoreException {

        if(mbd.isAbstract()){
            throw new BeanIsAbstractException(beanName);
        }
    }

    /**
     * Remove the merged bean definition for the specified bean,
     * recreating it on next access.
     * @param beanName the bean name to clear the merged definition for
     */
    protected void clearMergedBeanDefinition(String beanName) {
        RootBeanDefinition bd = this.mergedBeanDefinitions.get(beanName);
        if(bd != null){
            bd.stale = true;
        }
    }

    /**
     * Clear the merged bean definition cache, removing entries for beans
     * which are not considered eligible for full metadata caching yet.
     * <p>Typically triggered after changes to the original bean definitions,
     * e.g. after applying a {@code BeanFactoryPostProcessor}. Note that metadata
     * for beans which have already been created at this point will be kept around.
     * @since 4.2
     */
    public void clearMetadataCache() {
        this.mergedBeanDefinitions.forEach((beanName, bd) -> {
            if(!isBeanEligibleForMetadataCaching(beanName)){
                bd.stale = true;
            }
        });
    }

    /**
     * Resolve the bean class for the specified bean definition,
     * resolving a bean class name into a Class reference (if necessary)
     * and storing the resolved Class in the bean definition for further use.
     * @param mbd          the merged bean definition to determine the class for
     * @param beanName     the name of the bean (for error handling purposes)
     * @param typesToMatch the types to match in case of internal type matching purposes
     *                     (also signals that the returned {@code Class} will never be exposed to application code)
     * @return the resolved bean class (or {@code null} if none)
     * @throws CannotLoadBeanClassException if we failed to load the class
     */
    @Nullable
    protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName,
                                        final Class<?>... typesToMatch) throws CannotLoadBeanClassException {

        try{
            if(mbd.hasBeanClass()){
                return mbd.getBeanClass();
            }
            if(System.getSecurityManager() != null){
                return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)() -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
            }else{
                return doResolveBeanClass(mbd, typesToMatch);
            }
        }catch(PrivilegedActionException pae){
            ClassNotFoundException ex = (ClassNotFoundException)pae.getException();
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
        }catch(ClassNotFoundException ex){
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
        }catch(LinkageError err){
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
        }
    }

    @Nullable
    private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException {

        ClassLoader beanClassLoader = getBeanClassLoader();
        ClassLoader dynamicLoader = beanClassLoader;
        boolean freshResolve = false;

        if(!ObjectUtils.isEmpty(typesToMatch)){
            // When just doing type checks (i.e. not creating an actual instance yet),
            // use the specified temporary class loader (e.g. in a weaving scenario).
            ClassLoader tempClassLoader = getTempClassLoader();
            if(tempClassLoader != null){
                dynamicLoader = tempClassLoader;
                freshResolve = true;
                if(tempClassLoader instanceof DecoratingClassLoader){
                    DecoratingClassLoader dcl = (DecoratingClassLoader)tempClassLoader;
                    for(Class<?> typeToMatch: typesToMatch){
                        dcl.excludeClass(typeToMatch.getName());
                    }
                }
            }
        }
        // 获取 BeanDefinition 的 beanClassName
        String className = mbd.getBeanClassName();
        if(className != null){
            // 根据 className 动态解析成表达式
            Object evaluated = evaluateBeanDefinitionString(className, mbd);
            if(!className.equals(evaluated)){
                // A dynamically resolved expression, supported as of 4.2...
                if(evaluated instanceof Class){
                    return (Class<?>)evaluated;
                }else if(evaluated instanceof String){
                    className = (String)evaluated;
                    freshResolve = true;
                }else{
                    throw new IllegalStateException("Invalid class name expression result: " + evaluated);
                }
            }
            if(freshResolve){
                // When resolving against a temporary class loader, exit early in order
                // to avoid storing the resolved Class in the bean definition.
                if(dynamicLoader != null){
                    try{
                        // 如果解析后的表达式是 Class，则直接返回
                        return dynamicLoader.loadClass(className);
                    }catch(ClassNotFoundException ex){
                        if(logger.isTraceEnabled()){
                            logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
                        }
                    }
                }
                // 反射方法加载类
                return ClassUtils.forName(className, dynamicLoader);
            }
        }

        // Resolve regularly, caching the result in the BeanDefinition...
        // className 不存在，则使用 ClassLoader 加载类
        return mbd.resolveBeanClass(beanClassLoader);
    }

    /**
     * Evaluate the given String as contained in a bean definition,
     * potentially resolving it as an expression.
     * @param value          the value to check
     * @param beanDefinition the bean definition that the value comes from
     * @return the resolved value
     * @see #setBeanExpressionResolver
     */
    @Nullable
    protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
        if(this.beanExpressionResolver == null){
            return value;
        }

        Scope scope = null;
        if(beanDefinition != null){
            String scopeName = beanDefinition.getScope();
            if(scopeName != null){
                scope = getRegisteredScope(scopeName);
            }
        }
        return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
    }

    /**
     * Predict the eventual bean type (of the processed bean instance) for the
     * specified bean. Called by {@link #getType} and {@link #isTypeMatch}.
     * Does not need to handle FactoryBeans specifically, since it is only
     * supposed to operate on the raw bean type.
     * <p>This implementation is simplistic in that it is not able to
     * handle factory methods and InstantiationAwareBeanPostProcessors.
     * It only predicts the bean type correctly for a standard bean.
     * To be overridden in subclasses, applying more sophisticated type detection.
     * @param beanName     the name of the bean
     * @param mbd          the merged bean definition to determine the type for
     * @param typesToMatch the types to match in case of internal type matching purposes
     *                     (also signals that the returned {@code Class} will never be exposed to application code)
     * @return the type of the bean, or {@code null} if not predictable
     */
    @Nullable
    protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
        Class<?> targetType = mbd.getTargetType();
        if(targetType != null){
            return targetType;
        }
        if(mbd.getFactoryMethodName() != null){
            return null;
        }
        return resolveBeanClass(mbd, beanName, typesToMatch);
    }

    /**
     * Check whether the given bean is defined as a {@link FactoryBean}.
     * @param beanName the name of the bean
     * @param mbd      the corresponding bean definition
     */
    protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
        Boolean result = mbd.isFactoryBean;
        if(result == null){
            Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
            result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
            mbd.isFactoryBean = result;
        }
        return result;
    }

    /**
     * Determine the bean type for the given FactoryBean definition, as far as possible.
     * Only called if there is no singleton instance registered for the target bean
     * already. Implementations are only allowed to instantiate the factory bean if
     * {@code allowInit} is {@code true}, otherwise they should try to determine the
     * result through other means.
     * <p>If no {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE} if set on the bean definition
     * and {@code allowInit} is {@code true}, the default implementation will create
     * the FactoryBean via {@code getBean} to call its {@code getObjectType} method.
     * Subclasses are encouraged to optimize this, typically by inspecting the generic
     * signature of the factory bean class or the factory method that creates it. If
     * subclasses do instantiate the FactoryBean, they should consider trying the
     * {@code getObjectType} method without fully populating the bean. If this fails, a
     * full FactoryBean creation as performed by this implementation should be used as
     * fallback.
     * @param beanName  the name of the bean
     * @param mbd       the merged bean definition for the bean
     * @param allowInit if initialization of the FactoryBean is permitted
     * @return the type for the bean if determinable, otherwise {@code ResolvableType.NONE}
     * @see org.springframework.beans.factory.FactoryBean#getObjectType()
     * @see #getBean(String)
     * @since 5.2
     */
    protected ResolvableType getTypeForFactoryBean(String beanName, RootBeanDefinition mbd, boolean allowInit) {
        ResolvableType result = getTypeForFactoryBeanFromAttributes(mbd);
        if(result != ResolvableType.NONE){
            return result;
        }

        if(allowInit && mbd.isSingleton()){
            try{
                FactoryBean<?> factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
                Class<?> objectType = getTypeForFactoryBean(factoryBean);
                return (objectType != null)?ResolvableType.forClass(objectType):ResolvableType.NONE;
            }catch(BeanCreationException ex){
                if(ex.contains(BeanCurrentlyInCreationException.class)){
                    logger.trace(LogMessage.format("Bean currently in creation on FactoryBean type check: %s", ex));
                }else if(mbd.isLazyInit()){
                    logger.trace(LogMessage.format("Bean creation exception on lazy FactoryBean type check: %s", ex));
                }else{
                    logger.debug(LogMessage.format("Bean creation exception on non-lazy FactoryBean type check: %s",
                            ex));
                }
                onSuppressedException(ex);
            }
        }
        return ResolvableType.NONE;
    }

    /**
     * Determine the bean type for a FactoryBean by inspecting its attributes for a
     * {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE} value.
     * @param attributes the attributes to inspect
     * @return a {@link ResolvableType} extracted from the attributes or
     *         {@code ResolvableType.NONE}
     * @since 5.2
     */
    ResolvableType getTypeForFactoryBeanFromAttributes(AttributeAccessor attributes) {
        Object attribute = attributes.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE);
        if(attribute instanceof ResolvableType){
            return (ResolvableType)attribute;
        }
        if(attribute instanceof Class){
            return ResolvableType.forClass((Class<?>)attribute);
        }
        return ResolvableType.NONE;
    }

    /**
     * Determine the bean type for the given FactoryBean definition, as far as possible.
     * Only called if there is no singleton instance registered for the target bean already.
     * <p>The default implementation creates the FactoryBean via {@code getBean}
     * to call its {@code getObjectType} method. Subclasses are encouraged to optimize
     * this, typically by just instantiating the FactoryBean but not populating it yet,
     * trying whether its {@code getObjectType} method already returns a type.
     * If no type found, a full FactoryBean creation as performed by this implementation
     * should be used as fallback.
     * @param beanName the name of the bean
     * @param mbd      the merged bean definition for the bean
     * @return the type for the bean if determinable, or {@code null} otherwise
     * @see org.springframework.beans.factory.FactoryBean#getObjectType()
     * @see #getBean(String)
     * @deprecated since 5.2 in favor of {@link #getTypeForFactoryBean(String, RootBeanDefinition, boolean)}
     */
    @Nullable
    @Deprecated
    protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) {
        return getTypeForFactoryBean(beanName, mbd, true).resolve();
    }

    /**
     * Mark the specified bean as already created (or about to be created).
     * <p>This allows the bean factory to optimize its caching for repeated
     * creation of the specified bean.
     * @param beanName the name of the bean
     */
    protected void markBeanAsCreated(String beanName) {
        //双重检查锁机制
        if(!this.alreadyCreated.contains(beanName)){
            synchronized(this.mergedBeanDefinitions){
                if(!this.alreadyCreated.contains(beanName)){
                    // Let the bean definition get re-merged now that we're actually creating
                    // the bean... just in case some of its metadata changed in the meantime.
                    // 将原先合并之后的RootBeanDefinition的需要重新合并的状态设置为true
                    // 表示需要重新合并一遍，以防原数据的改动
                    /**    <bean id="parent" class="com.imooc.Parent">
                     <property name="name" value="ouyangfeng"/>
                     </bean>
                     <!--下面的parent表示这个child的bean的父亲是id=parent的这个类-->
                     <bean id="child" class="com.imooc.Child" parent="parent">
                     <property name="age" value="18"/>
                     </bean>*/
                    clearMergedBeanDefinition(beanName);
                    //将已经创建好的或者正在创建的Bean的名称加到alreadyCreated这个缓存中
                    this.alreadyCreated.add(beanName);
                }
            }
        }
    }

    /**
     * Perform appropriate cleanup of cached metadata after bean creation failed.
     * @param beanName the name of the bean
     */
    protected void cleanupAfterBeanCreationFailure(String beanName) {
        synchronized(this.mergedBeanDefinitions){
            this.alreadyCreated.remove(beanName);
        }
    }

    /**
     * Determine whether the specified bean is eligible for having
     * its bean definition metadata cached.
     * @param beanName the name of the bean
     * @return {@code true} if the bean's metadata may be cached
     *         at this point already
     */
    protected boolean isBeanEligibleForMetadataCaching(String beanName) {
        return this.alreadyCreated.contains(beanName);
    }

    /**
     * Remove the singleton instance (if any) for the given bean name,
     * but only if it hasn't been used for other purposes than type checking.
     * @param beanName the name of the bean
     * @return {@code true} if actually removed, {@code false} otherwise
     */
    protected boolean removeSingletonIfCreatedForTypeCheckOnly(String beanName) {
        if(!this.alreadyCreated.contains(beanName)){
            removeSingleton(beanName);
            return true;
        }else{
            return false;
        }
    }

    /**
     * Check whether this factory's bean creation phase already started,
     * i.e. whether any bean has been marked as created in the meantime.
     * @see #markBeanAsCreated
     * @since 4.2.2
     */
    protected boolean hasBeanCreationStarted() {
        return !this.alreadyCreated.isEmpty();
    }

    /**
     * Get the object for the given bean instance, either the bean
     * instance itself or its created object in case of a FactoryBean.
     * @param beanInstance the shared bean instance
     * @param name         name that may include factory dereference prefix
     * @param beanName     the canonical bean name
     * @param mbd          the merged bean definition
     * @return the object to expose for the bean
     */
    protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName,
                                              @Nullable RootBeanDefinition mbd) {

        // Don't let calling code try to dereference the factory if the bean isn't a factory.
        if(BeanFactoryUtils.isFactoryDereference(name)){
            if(beanInstance instanceof NullBean){
                return beanInstance;
            }
            //如果name是以&开头的 但是不是FactoryBean，则直接抛出异常
            if(!(beanInstance instanceof FactoryBean)){
                throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
            }
            if(mbd != null){
                mbd.isFactoryBean = true;
            }
            return beanInstance;
        }

        // Now we have the bean instance, which may be a normal bean or a FactoryBean.
        // If it's a FactoryBean, we use it to create a bean instance, unless the
        // caller actually wants a reference to the factory.
        // 如果是一个普通的bean，则直接返回
        if(!(beanInstance instanceof FactoryBean)){
            return beanInstance;
        }
        //FactoryBean创建出bean实例返回
        Object object = null;
        if(mbd != null){
            mbd.isFactoryBean = true;
        }else{
            //单例模式下，FactoryBean仅会创建一个Bean实例，
            // 因此需要优先从缓存获取
            object = getCachedObjectForFactoryBean(beanName);
        }
        if(object == null){
            //若缓存没有则尝试创建
            // Return bean instance from factory.
            FactoryBean<?> factory = (FactoryBean<?>)beanInstance;
            // Caches object obtained from FactoryBean if it is a singleton.
            if(mbd == null && containsBeanDefinition(beanName)){
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

    /**
     * Determine whether the given bean name is already in use within this factory,
     * i.e. whether there is a local bean or alias registered under this name or
     * an inner bean created with this name.
     * @param beanName the name to check
     */
    public boolean isBeanNameInUse(String beanName) {
        return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName);
    }

    /**
     * Determine whether the given bean requires destruction on shutdown.
     * <p>The default implementation checks the DisposableBean interface as well as
     * a specified destroy method and registered DestructionAwareBeanPostProcessors.
     * @param bean the bean instance to check
     * @param mbd  the corresponding bean definition
     * @see org.springframework.beans.factory.DisposableBean
     * @see AbstractBeanDefinition#getDestroyMethodName()
     * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
     */
    protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
        return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (
                hasDestructionAwareBeanPostProcessors()
                        && DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
    }

    /**
     * Add the given bean to the list of disposable beans in this factory,
     * registering its DisposableBean interface and/or the given destroy method
     * to be called on factory shutdown (if applicable). Only applies to singletons.
     * @param beanName the name of the bean
     * @param bean     the bean instance
     * @param mbd      the bean definition for the bean
     * @see RootBeanDefinition#isSingleton
     * @see RootBeanDefinition#getDependsOn
     * @see #registerDisposableBean
     * @see #registerDependentBean
     */
    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
        AccessControlContext acc = (System.getSecurityManager() != null?getAccessControlContext():null);
        // 不是prototype且需要销毁
        if(!mbd.isPrototype() && requiresDestruction(bean, mbd)){
            if(mbd.isSingleton()){
                // Register a DisposableBean implementation that performs all destruction
                // work for the given bean: DestructionAwareBeanPostProcessors,
                // DisposableBean interface, custom destroy method.
                // 单例模式下需要销毁的bean
                registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd,
                        getBeanPostProcessors(), acc));
            }else{
                // A bean with a custom scope...
                // 自定义scope的处理
                Scope scope = this.scopes.get(mbd.getScope());
                if(scope == null){
                    throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
                }
                scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(bean, beanName, mbd,
                        getBeanPostProcessors(), acc));
            }
        }
    }

    //---------------------------------------------------------------------
    // Abstract methods to be implemented by subclasses
    //---------------------------------------------------------------------

    /**
     * Check if this bean factory contains a bean definition with the given name.
     * Does not consider any hierarchy this factory may participate in.
     * Invoked by {@code containsBean} when no cached singleton instance is found.
     * <p>Depending on the nature of the concrete bean factory implementation,
     * this operation might be expensive (for example, because of directory lookups
     * in external registries). However, for listable bean factories, this usually
     * just amounts to a local hash lookup: The operation is therefore part of the
     * public interface there. The same implementation can serve for both this
     * template method and the public interface method in that case.
     * @param beanName the name of the bean to look for
     * @return if this bean factory contains a bean definition with the given name
     * @see #containsBean
     * @see org.springframework.beans.factory.ListableBeanFactory#containsBeanDefinition
     */
    protected abstract boolean containsBeanDefinition(String beanName);

    /**
     * Return the bean definition for the given bean name.
     * Subclasses should normally implement caching, as this method is invoked
     * by this class every time bean definition metadata is needed.
     * <p>Depending on the nature of the concrete bean factory implementation,
     * this operation might be expensive (for example, because of directory lookups
     * in external registries). However, for listable bean factories, this usually
     * just amounts to a local hash lookup: The operation is therefore part of the
     * public interface there. The same implementation can serve for both this
     * template method and the public interface method in that case.
     * @param beanName the name of the bean to find a definition for
     * @return the BeanDefinition for this prototype name (never {@code null})
     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException if the bean definition cannot be resolved
     * @throws BeansException                                                  in case of errors
     * @see RootBeanDefinition
     * @see ChildBeanDefinition
     * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition
     */
    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    /**
     * Create a bean instance for the given merged bean definition (and arguments).
     * The bean definition will already have been merged with the parent definition
     * in case of a child definition.
     * <p>All bean retrieval methods delegate to this method for actual bean creation.
     * @param beanName the name of the bean
     * @param mbd      the merged bean definition for the bean
     * @param args     explicit arguments to use for constructor or factory method invocation
     * @return a new instance of the bean
     * @throws BeanCreationException if the bean could not be created
     */
    protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException;

}
